/*! \defgroup modelviews Model Views */

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Project Name: ARS Logs Reader
// Version: 1.0
// File Name: 'logfilewidget.h'
// Purpose: 'LogFileWidget', 'LogTableModel', classes declaration
//
////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __LOG_FILE_WIDGET_H
#define __LOG_FILE_WIDGET_H

///////// Include Files ////////////////////////////////////////////////////////////////////////////

#include <QTreeWidget>
#include <QRegExp>
#include <QItemDelegate>
#include <QPainter>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsWidget>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsLinearLayout>
#include <QTimer>
#include <QToolBar>
#include <QSortFilterProxyModel>
#include <QPair>
#include <QLabel>
#include <QTextEdit>
#include <QDialog>
#include <QGraphicsDropShadowEffect>
#include <QStackedWidget>
#include <QComboBox>
#include <QToolButton>
#include <QCompleter>

#include <viewinterface.h>
#include <arsobject.h>
#include <dynamicmodel.h>
#include <viewwidget.h>

#include "treeviewmodel.h"

//#include "searchfilter.h"
//#include "settings.h"

class TreeView;
class TreeViewDelegate;
class DetailsButton;
class ObjectDetailsWidget;
class ObjectDetailsButton;
class CommentWidget;
class ARSObjectWidget;
class ARSObjectTitleWidget;
class ARSObjectPropertiesWidget;
class CommentTextEdit;
class BranchRootTooltipWidget;
class SearchWidget;
class BranchScrollerWidget;
class CommentEditWidget;
class ShadowWidget;
class LeftMarginWidget;
class ItemsListWidget;
class DockWidget;
class DockTitleLabel;
class CommentEditDialog;
class TreeViewSearchModel;

////////////////////////////////////////////////////////////////////////////////////////////////////
///////// Tree View ////////////////////////////////////////////////////////////////////////////////

///////// Class 'DebugTreeFieldIndex' declaration //////////////////////////////////////////////////

class DebugTreeFieldIndex
{
public:
    enum FieldRole
    {
        None,
        Label,
        Value
    };

    DebugTreeFieldIndex();
    DebugTreeFieldIndex( QModelIndex itemIndex, QString propertyName );

    bool isValid() const;
    QModelIndex itemIndex() const;
    QString propertyName() const;

private:
    QModelIndex m_itemIndex;
    QString m_propertyName;
};

typedef QList<DebugTreeFieldIndex> DebugTreeFieldIndexList;

///////// Class 'TreeView' declaration ////////////////////////////////////////////////////////

class TreeView : public QTreeView
{
    Q_OBJECT
    Q_PROPERTY( int scaleSize READ scaleSize WRITE setScaleSize )

public:
    enum DataRoles
    {
        RoleItemType = Qt::UserRole,
        RoleWorkflowObjectType,
        RoleItemID,
        RoleItem,
        RoleItemSearchMatch,
        RoleItemHiddenReason
    };

    enum HiddenReasons
    {
        HiddenBySearchFilter,
        HiddenByHideEmpty
    };

    enum EditItemType
    {
        Comment,
        None
    };

    TreeView( QWidget * parent = 0 );

//    ARSExecAction::ActionType actionsFilter() const;
//    void setActionsFilter( ARSExecAction::ActionType filter );
//    bool showEmptyWorkflow() const;
//    bool docViewActive();
//    void setDocViewActive( bool active );
    void copy();

    void mouseMoveEvent( QMouseEvent * event );
    void mousePressEvent( QMouseEvent * event );
    void mouseDoubleClickEvent( QMouseEvent *event );
    void leaveEvent( QEvent * event );
    void scrollContentsBy( int dx, int dy );
    void resizeEvent( QResizeEvent *event );
    void drawBranchess( QPainter * painter, const QRect & rect, const QModelIndex & index ) const;
    void paintEvent( QPaintEvent * event );
    QModelIndexList matchedItems();
    QModelIndex matchedFocusItem();
    int maxRowWidth();
    TreeViewModel * treeViewModel() const;
    void setTreeViewModel(TreeViewModel * model);
    void generateScreenPos();
    DebugTreeFieldIndex hoveredField();
    DebugTreeFieldIndex selectedField();
    DebugTreeFieldIndexList highlightedItems() const;
    void highlightItems( const DebugTreeFieldIndexList & itemsList );
    QString highlightedField( const QModelIndex & index );
    void removeHighlight();
    const QModelIndexList & bookmarkList() const;
    void checkHoveredItems();
    QRect myVisualRect( const QModelIndex & index );
    void updateStyleGeometry();
    int scaleSize() const;
    void setScaleSize( int size );
    QModelIndex highlightItem();
    void setHighlightedItem( const QModelIndex & index );
    TreeViewFilterProxyModel::FilterMode filterMode() const;

signals:
    void objectClicked( ARSDummyObject * object );
    void commentAdded();
    void focusItemTypeChanged( TreeView::EditItemType type );
    void bookmarkAdded( const QModelIndex & index );
    void bookmarkRemoved( const QModelIndex & index );
    void screenPosChanged( const QModelIndex & top, const QModelIndex & bottom );
    void modified();

public slots:
    void itemUnderMouseChanged( ARSExecItem * item );
//    void search( SearchQualificationList qualification, DynamicModel::SearchDirection direction );
    void gotoItem( const QModelIndex & index, bool centerItem = true, bool ignoreVisibility = false );
    void animateItem( const QModelIndex & index );
    void copyItem();
    void setFilterMode( TreeViewFilterProxyModel::FilterMode mode );

private:
    int findMaxItemWidth();

    static const int DisabledShadowTransparency = 100;
    static const int BranchTooltipHeight = 16;
    static const int MarginWidth = 20;

    QHash<TreeViewFilterProxyModel::FilterMode, TreeViewFilterProxyModel *> m_filterModels;
    TreeViewFilterProxyModel::FilterMode m_currentFilterMode;
    TreeViewModel * m_model;

    // States
    bool m_searchActive;
    bool m_showEmptyWorkflow;
    ARSExecAction::ActionType m_actionsFilter;
    bool m_docViewActive;
    bool m_commentEditing;
    double m_shadowAnimationProcess;

    // Comments
    CommentEditDialog * m_commentEditDialog;
    QModelIndex m_commentIndex;

    // Bookmarks
    QModelIndexList m_bookmarksList;

    // Mouse tracking
    DebugTreeFieldIndex m_hoveredField;
    DebugTreeFieldIndex m_selectedField;
    BranchRootTooltipWidget * m_branchTooltipWidget;
    QModelIndex m_hoveredBranch;
    QModelIndex m_highlightedItem;
    int m_scaleSize;

    DebugTreeFieldIndexList m_highlightedItems;
    int m_maxItemWidth;
    int m_repaint_counter;
    QModelIndex m_itemUnderMenu;
};

///////// Class 'TreeViewDelegate' declaration /////////////////////////////////////////////////////

class TreeViewDelegate : public QItemDelegate
{
    Q_OBJECT

public:
    enum HighlightRole
    {
        HighlightNone = 0,
        HighlightHovered = 1,
        HighlightSearchResult = 2,
        HighlightSelected = 4
    };

    TreeViewDelegate( TreeView * parent );
    virtual void paint( QPainter * painter,
                        const QStyleOptionViewItem & option,
                        const QModelIndex & index ) const;

    QSize sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
    static void drawItem( const QModelIndex & index, QPainter * painter,
                                  const QRect & rect, bool singleLine = false );
    static QRect drawField( QPainter * painter, ARSExecItem * item, const QString & propertyName,
                            QRect rect, PropertyStyle * propertyStyle = 0,
                            HighlightRole highlightRole = HighlightNone, int alpha = 255);
    static QSize itemVisualSize( const QModelIndex & index, bool singleLine = false );
    static QString item2String( const ARSExecItem * item );
    static QString field2String( const ARSExecItem * item, const QString propertyName );
    static QString fieldPropertyName( const QModelIndex & index, int dx, int dy, bool singleLine = false );
    static QSize fieldSize( const ARSExecItem * item, const QString propertyName, bool singleLine = false );
/*    QWidget * createEditor( QWidget * parent, const QStyleOptionViewItem & option,
                            const QModelIndex & index ) const;
    void setEditorData( QWidget * editor, const QModelIndex & index ) const;
    void setModelData ( QWidget * editor, QAbstractItemModel * model, const QModelIndex & index ) const;
    void updateEditorGeometry( QWidget * editor, const QStyleOptionViewItem & option,
                               const QModelIndex & index ) const;*/

private:
    static const int SpacingInsideProperty = 6;
    static const int SpacingBetweenProperties = 6;
    TreeView * m_parentView;
    mutable const ARSDummyObject * m_objectUnderMouse;
    mutable QModelIndex m_indexUnderMouse;
};

///////// Class 'BranchScrollerWidget' declaration /////////////////////////////////////////////////

class BranchScrollerWidget : public QWidget
{
    Q_OBJECT

public:
    static const int scrollerWidth = 12;
    static const int scrollerHeight = 30;

    BranchScrollerWidget( QWidget * parent = 0 );
//    BranchFrame frame();

    void paintEvent( QPaintEvent * event );
//    void leaveEvent( QEvent * event );

private:
//    BranchFrame m_frame;
};

///////// Class 'DockTitleLabel' declaration //////////////////////////////////////////////////////

class DockTitleLabel : public QWidget
{
    Q_OBJECT

public:
    DockTitleLabel( QWidget * parent = 0 );
    void setText( const QString & text );
    void paintEvent( QPaintEvent * event );

private:
    QString m_text;
};

///////// Class 'DockTitleWidget' declaration //////////////////////////////////////////////////////

class DockTitleWidget : public QWidget
{
    Q_OBJECT

public:
    static const int MarginWidth = 20;

    DockTitleWidget(QWidget * parent = 0);
    void paintEvent( QPaintEvent * event );
    void setText( const QString & text );

signals:
    void closeClicked();

private:
    DockTitleLabel * m_title;
    QToolButton * m_closeButton;
};

///////// Class 'DockWidget' declaration ///////////////////////////////////////////////////////////

class DockWidget : public QWidget
{
    Q_OBJECT

public:
    enum Widget
    {
        None,
        Bookmarks,
        SearchItems,
        SearchResults
    };

    DockWidget( QWidget * parent = 0 );
    void setWidget( Widget widget );
    Widget currentWidget();
    ItemsListWidget * bookmarksListWidget();
    SearchWidget * searchWidget();
    ItemsListWidget * searchResultsListWidget();
    void addBookMark( const QModelIndex & index );
    void removeBookMark( const QModelIndex & index );

signals:
    void closeClicked();

private:
    DockTitleWidget * m_title;
    ItemsListWidget * m_bookmarksListWidget;
    ItemsListWidget * m_searchResultsListWidget;
    QStackedWidget * m_stack;
};

///////// Class 'DebugWidget' declaration //////////////////////////////////////////////////////////

class TreeViewWidget : public DynamicViewWidget
{
    Q_OBJECT

public:
    TreeViewWidget(QWidget * parent = 0);

    void setModel(DynamicModel * model);
    QString pluginName() const;
    void connectToolBarItems(const ToolBarItemList &items);
    void disconnectToolBarItems(const ToolBarItemList &items);
    void adjustToolbar(const ToolBarItemList & itemsList) const;
    TreeView * treeWidget();
    void showDockWidget( DockWidget::Widget widget );
    DockWidget::Widget dockCurrentWidget() const;

    void keyPressEvent( QKeyEvent * event );

signals:
    void openItem(ARSExecItem *item);
    void objectClicked( ARSDummyObject * object );
    void dockWidgetChanged( DockWidget::Widget widget );
    void modified();

public slots:
    void hideDockWidget();
    void searchObject( ARSDummyObject * object );
    void showObjectDetails( const ARSObject * object );
    void commentAdded();
    void commentFocusTypeChanged( TreeView::EditItemType type );
    void addBookmarkToDock( const QModelIndex & index );
    void removeBookmarkFromDock( const QModelIndex & index );
    void gotoBookmark( const QModelIndex & index, bool closeList );
    void gotoSearchResult( const QModelIndex & index, bool closeList );
    void setScreenPos( const QModelIndex & top, const QModelIndex & bottom );
    void gotoItem( ARSExecItem * item );
    void expand();
    void collapse();
    void showAllWorkflow(bool yes);
    void hideEmptyWorkflow(bool yes);
    void hideInternalWorkflow(bool yes);
    void copyItem();
    void showBookmarks(bool show);

private:
    TreeView * m_treeWidget;
    DockWidget * m_dockWidget;
    TreeViewModel * m_model;
    TreeViewSearchModel * m_searchModel;
    QAction * m_bookmarksAction;
};

class CommentEditDialog : public QDialog
{
    Q_OBJECT

public:
    CommentEditDialog( QWidget * parent );
    bool eventFilter( QObject * object, QEvent * event );
    void setText( const QString & text );
    QString text();

private:
    QTextEdit * m_edit;
    QString * m_resultText;
};

///////// Class 'LeftMarginWidget' declaration /////////////////////////////////////////////////////

class LeftMarginWidget: public QWidget
{
    Q_OBJECT

public:
    static const int marginWidth = 20;

    LeftMarginWidget( QWidget * parent = 0 );
    void paintEvent( QPaintEvent * event );
    void setBookMarksList( const QList<int> & list );
    void mousePressEvent( QMouseEvent * );

signals:
    void clicked( int yPos );

private:
    QList<int> m_bookmarksList;
};

///////// Class 'ItemsListMarginWidget' declaration ////////////////////////////////////////////////

class ItemsListMarginWidget : public QWidget
{
    Q_OBJECT

public:
    static const int widgetWidth = 10;

    ItemsListMarginWidget(QWidget * parent = 0 );
    void setPointerPos( int top, int bottom = -1);
    bool pointerIsVisible() const;
    void setPointerVisible( bool visible );

    void paintEvent( QPaintEvent * event );

private:
    int m_topPointerPos;
    int m_bottomPointerPos;
    bool m_showPointer;
};

///////// Class 'ItemsListWidget' declaration //////////////////////////////////////////////////////

Q_DECLARE_METATYPE(QModelIndex)

class ItemsListWidget: public QTreeWidget
{
    Q_OBJECT

public:
    enum ItemRoles
    {
        RoleIndex = Qt::UserRole,
        RoleHighlight
    };

    ItemsListWidget( QWidget * parent = 0 );
    void setItemsList( const QModelIndexList & indexList );
    void addItem( const QModelIndex & index );
    void removeItem( const QModelIndex & index );
    void setScreenPos( const QModelIndex & top, const QModelIndex & bottom );
    void mouseMoveEvent( QMouseEvent *event );
    void leaveEvent( QEvent * event );
    void scrollContentsBy( int dx, int dy );

signals:
    void itemClicked( const QModelIndex & index, bool doubleClicked );

private slots:
    void itemIsClicked( QTreeWidgetItem * item );
    void itemIsDoubleClicked( QTreeWidgetItem * item );

private:
    void setHighlighted( QTreeWidgetItem * item );
    int findPlaceForItem( const QModelIndex & index );
    int findItem( const QModelIndex & index );

    QModelIndex m_topScreenPointIndex;
    QModelIndex m_bottomScreenPointIndex;
    ItemsListMarginWidget * m_marginWidget;
    QTreeWidgetItem * m_highlightedItem;
};

///////// Class 'ItemsListDelegate' declaration ////////////////////////////////////////////////////

class ItemsListDelegate: public QItemDelegate
{
    Q_OBJECT

public:
    ItemsListDelegate( QObject * parent = 0 );
    void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
    QSize sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index) const;
};

///////// Class 'TreeViewSearchModel' declaration //////////////////////////////////////////////////

class TreeViewSearchModel : public QAbstractListModel
{
    Q_OBJECT

public:
    TreeViewSearchModel(const ARSDummyObjectList & list, QObject * parent = 0);

    int rowCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;

private:
    ARSDummyObjectList m_list;
    QHash<ARSObject::Type, QIcon> m_iconMap;
};

///////// Class 'TreeViewSearchWidget' declaration /////////////////////////////////////////////////

class TreeViewSearchWidget : public QWidget
{
    Q_OBJECT

public:
    TreeViewSearchWidget(QWidget * parent = 0);
    void setModel(TreeViewSearchModel * model);
    ARSDummyObject * currentObject() const;

public slots:
    void searchButtonClicked();
    void textChanged();
    void itemSelected(int index);

signals:
    void searchObject(ARSDummyObject * object);
//    void searchText(const QString & text);

private:
    QComboBox * m_comboBox;
    QToolButton * m_SearchButton;
};

///////// Class 'TreeViewPlugin' declaration ///////////////////////////////////////////////////////

class TreeViewPlugin : public QObject,
                       public ViewPluginInterface
{
    Q_OBJECT
    Q_INTERFACES(PluginInterface ViewPluginInterface)

public:
    TreeViewPlugin(QObject * parent = 0);

    QString name()const;
    QString description()const;
    bool loadSettings();
    QString viewName()const;
    ViewWidget::ViewType viewType() const;
    QIcon icon(bool active)const;
    DynamicViewWidget * createView(QWidget * parent = 0)const;
    ToolBarItemList toolBarItems(QObject * parent)const;
    SettingsWidget * settingsWidget(QWidget * parent = 0)const;
    void appEvent(AppEvent * event);
};

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif // __LOG_FILE_WIDGET_H

////////////////////////////////////////////////////////////////////////////////////////////////////
